package site.teamo.biu.net.common.http_https_proxy;

import io.netty.channel.Channel;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import site.teamo.biu.net.common.constant.ChannelAttributeKey;
import site.teamo.biu.net.common.util.HostPort;

import java.util.Optional;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * @author haocongshun
 * @date 2023/06/08 16:12:25
 */
@Slf4j
public class ChannelGroups extends ConcurrentHashMap<HostPort, ChannelGroups.Channels> {

    private Timer cleaner;

    public ChannelGroups() {
        this.cleaner = new Timer();
        cleaner.schedule(new TimerTask() {
            @Override
            public void run() {
                clean();
            }
        }, 0, 10000);
    }

    public void put(HostPort key, Channel channel) {
        Channels channels = this.getOrDefault(key, new Channels());
        channels.add(channel);
        this.put(key, channels);
    }

    public void close() {
        this.values().forEach(Channels::close);
        this.clear();
    }

    public void clean() {
        this.values().forEach(Channels::clean);
        this.entrySet().removeIf(e -> e.getValue().size() == 0);
    }


    public static class Channels extends CopyOnWriteArrayList<Channel> {
        @Getter
        private final long timestamp;

        public Channels() {
            this.timestamp = System.currentTimeMillis();
        }

        public void close() {
            for (Channel channel : this) {
                if (channel.isActive() || channel.isOpen()) {
                    channel.close();
                }
            }
        }

        public synchronized void clean() {
            this.removeIf(channel -> {
                boolean active = channel.isActive();
                if (!active) {
                    Optional.ofNullable(channel.attr(ChannelAttributeKey.DESTINATION_INFO).get())
                            .ifPresent(hostPort -> {
                                log.info("使用{}协议与{}:{}建立的连接已移除", hostPort.protocol(), hostPort.host(), hostPort.port());
                            });
                }
                return !active;
            });
        }
    }
}
